# this script walks through the steps needed to determine the RC time
#   constant and passive leak conductance of a cell from hyperpolarization
#   voltage traces.

import scipy
from numpy import histogram
from matplotlib.figure import Figure
from matplotlib.widgets import SpanSelector
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import cPickle
from genutils import special_functions
from genutils import handy_functions

import Tkinter as Tk


def find_rc(v_series,t_series, current):
    class empty:
        # an empty class definition to store global variables in.
        pass

    def calc_ylines(data,bins):
        # this function returns the two most represented y values given some data and a number of bins
        histo = histogram(data,bins=bins)
        # the index of the maximum value in the FIRST half of histo
        first_max_index = histo[0][:len(histo[0])/2].argsort()[-1]
        # the index of the maximum value in the LAST half of histo
        last_max_index = histo[0][len(histo[0])/2:].argsort()[-1]+len(histo[0])/2

        # the two steady state voltages are then histo[1] at those two indexes
        y_min = histo[1][first_max_index]
        y_max = histo[1][last_max_index]
        return y_min,y_max

    #-------------- RADIO BUTTONS -----------------------------
    # the functions called when the radio buttons are pressed.
    def set_fit_falling():
        falling_span.visible = True
        rising_span.visible = False
        dv_span.visible = False

    def set_fit_rising():
        falling_span.visible = False
        rising_span.visible = True
        dv_span.visible = False

    def set_adjust_dv():
        falling_span.visible = False
        rising_span.visible = False
        dv_span.visible = True


    #-------------- SPAN SELECTORS -----------------------------
    # the functions called when the span selectors are used.
    def fit_selection(t_start,t_end):
        # fit an exponential to the data and plot the results
        exp_parameters = handy_functions.exp_fit(t,v,t_start,t_end)
        scale = exp_parameters[0]
        xoff = exp_parameters[1]
        yoff = exp_parameters[2]
        tau = exp_parameters[3]
        t_fit = scipy.linspace(t_start,t_end,100) # 100 pts from t_start to t_end
        v_fit = special_functions.exp_decay(scale,xoff,yoff,tau,t_fit)
        return t_fit, v_fit, tau

    def fit_falling(t_start,t_end):
        # fit the falling exponential and then display it.
        t_fit, v_fit, tau = fit_selection(t_start,t_end)
        program_data.tau1 = tau
        falling_fig.ax.set_xlim(t_start,t_end)
        # set the data for the fit line
        falling_fig.fit_line.set_data(t_fit,v_fit)
        falling_fig.fig.canvas.draw()

    def fit_rising(t_start,t_end):
        # fit the rising exponential and then display it.
        t_fit, v_fit, tau = fit_selection(t_start,t_end)
        program_data.tau2 = tau
        rising_fig.ax.set_xlim(t_start,t_end)
        # set the data for the fit line
        rising_fig.fit_line.set_data(t_fit,v_fit)
        rising_fig.fig.canvas.draw()

    def adjust_dv(v_min,v_max):
        # adjust the horizontal lines on the main figure.
        program_data.v_min = v_min
        program_data.v_max = v_max
        del main_fig.ax.lines[-1]
        del main_fig.ax.lines[-1]
        main_fig.v_min_line = main_fig.ax.axhline(y=program_data.v_min,linewidth=1,color='r')
        main_fig.v_max_line = main_fig.ax.axhline(y=program_data.v_max,linewidth=1,color='r')
        main_fig.fig.canvas.draw()


#---------------- CALCULATE BUTTON ------------------------
    def calc_cell():
        # calculate the cell properties and display the results.
        program_data.avg_tau = (program_data.tau1 + program_data.tau2)/2
        program_data.dv = abs(program_data.v_min - program_data.v_max)
        program_data.g = abs(program_data.current)/program_data.dv
        # knowing R = 1/g we can find C knowing that tau=RC
        program_data.C = program_data.avg_tau * program_data.g
        line1 = "Vmin: %2.2f   Vmax: %2.2f   dV: %2.2f\n" % (program_data.v_min, program_data.v_max, program_data.dv)
        line2 = "Conductance: %2.6f uS\n" % (program_data.g)
        line3 = "Capacitance: %2.6f nF\n" % (program_data.C)
        line4 = "Tau1: %2.2f    Tau2: %2.2f  Avg: %2.2f" %\
                 (program_data.tau1,program_data.tau2,program_data.avg_tau)
        # delete the text in the text area and put new stuff back.
        calc_text_area.delete(1.0,Tk.END)
        calc_text_area.insert(Tk.END, line1+line2+line3+line4 )

    program_data = empty()
    program_data.current = current
    v = v_series
    t = t_series

    # open up the main application window
    root = Tk.Tk()
    root.wm_title("Fitting Hyperpolarization Data    (By David Morton - July 2008)")

    #-------------- MAIN PLOT --------------------------
    main_fig = empty()
    main_fig.fig = Figure(figsize=(7,3))
    main_fig.canvas = FigureCanvasTkAgg(main_fig.fig, master=root)
    main_fig.ax = main_fig.fig.add_subplot(111)
    main_fig.ax.set_title('Raw Data\nSelect the region to fit.')
    main_fig.fig.set_edgecolor('#FFFFFF')
    main_fig.fig.set_facecolor('#FFFFFF')
    main_fig.fig.subplots_adjust(top=0.80,bottom=0.1,left=0.1,right=0.9)
    main_fig.ax.plot(t,v)

    #-------------- FALLING FIT PLOT --------------------------
    falling_fig = empty()
    falling_fig.fig = Figure(figsize=(3,3))
    falling_fig.canvas = FigureCanvasTkAgg(falling_fig.fig, master=root)
    falling_fig.ax = falling_fig.fig.add_subplot(111)
    falling_fig.ax.set_title('Exponential Fit 1')
    falling_fig.fig.set_edgecolor('#FFFFFF')
    falling_fig.fig.set_facecolor('#FFFFFF')
    falling_fig.fig.subplots_adjust(top=0.85,bottom=0.15,left=0.15,right=0.9)
    falling_fig.fit_line, = falling_fig.ax.plot(t,v,lw=3,color='y')
    falling_fig.data_line, = falling_fig.ax.plot(t,v)
    falling_fig.ax.set_xlim(t[0],t[int(len(t)/2)])

    #-------------- RISING FIT PLOT --------------------------
    rising_fig = empty()
    rising_fig.fig = Figure(figsize=(3,3))
    rising_fig.canvas = FigureCanvasTkAgg(rising_fig.fig, master=root)
    rising_fig.ax = rising_fig.fig.add_subplot(111)
    rising_fig.ax.set_title('Exponential Fit 2')
    rising_fig.fig.set_edgecolor('#FFFFFF')
    rising_fig.fig.set_facecolor('#FFFFFF')
    rising_fig.fig.subplots_adjust(top=0.85,bottom=0.15,left=0.15,right=0.9)
    rising_fig.fit_line, = rising_fig.ax.plot(t,v,lw=3,color='y')
    rising_fig.data_line, = rising_fig.ax.plot(t,v)
    rising_fig.ax.set_xlim(t[int(len(t)/2)],t[-1])

    # the span selectors themselves.
    falling_span = SpanSelector(main_fig.ax,fit_falling,'horizontal',useblit=True,\
                        rectprops=dict(alpha=0.5,facecolor='blue') )
    rising_span = SpanSelector(main_fig.ax,fit_rising,'horizontal',useblit=True,\
                        rectprops=dict(alpha=0.5,facecolor='blue') )
    dv_span = SpanSelector(main_fig.ax,adjust_dv,'vertical',useblit=True,\
                        rectprops=dict(alpha=0.5,facecolor='red') )

    # the radio buttons themselves.
    buttons = []
    button_selected = Tk.IntVar()
    buttons.append( Tk.Radiobutton( root, text='Adjust dV', \
                    variable=button_selected,value=1,indicatoron=0,\
                    padx=10,pady=10,command=set_adjust_dv ))
    buttons.append( Tk.Radiobutton( root, text='Fit Falling', \
                    variable=button_selected,value=2,indicatoron=0,\
                    padx=10,pady=10,command=set_fit_falling ))
    buttons.append( Tk.Radiobutton( root, text='Fit Rising', \
                    variable=button_selected,value=3,indicatoron=0,\
                    padx=10,pady=10,command=set_fit_rising ))

    current_label = Tk.Label(root, text='Current (nA):')
    current_entry = Tk.Entry(root)
    current_entry.insert(Tk.END,str(current))
    calc_button = Tk.Button(master=root, text="Calculate Cell Properties", command=calc_cell)
    calc_text_area = Tk.Text(root,height=5,width=40)

    #---------------- GRID LAYOUT ----------------------------
    main_fig.canvas.get_tk_widget().grid(row=1,column=3,rowspan=3,columnspan=2)
    falling_fig.canvas.get_tk_widget().grid(row=10,column=3)
    rising_fig.canvas.get_tk_widget().grid(row=10,column=4)
    buttons[0].grid(row=1,column=1,columnspan=2) # adjust dv button
    buttons[1].grid(row=11,column=3) # fit_falling button
    buttons[2].grid(row=11,column=4) # fit_rising button
    current_label.grid(row=2,column=1,sticky=Tk.E)
    current_entry.grid(row=2,column=2,sticky=Tk.W)
    calc_button.grid(row=3,column=1,columnspan=2,sticky=Tk.S) 
    calc_text_area.grid(row=10,column=1,columnspan=2,sticky=Tk.N)



    #----------------- initialization ------------------------
    # initialize the dv lines.
    program_data.v_min,program_data.v_max = calc_ylines(v,50)
    # plot the maximum steady state voltage and minimum steady state voltage lines
    main_fig.v_min_line = main_fig.ax.axhline(y=program_data.v_min,linewidth=1,color='r')
    main_fig.v_max_line = main_fig.ax.axhline(y=program_data.v_max,linewidth=1,color='r')
    set_adjust_dv()
    Tk.mainloop()
    return program_data
    




 




